home *** CD-ROM | disk | FTP | other *** search
/ Network CD 2 / Network CD - Volume 2.iso / programs / internet / tcp / amitcp / amitcp-src-22.lha / AmiTCP-2.2 / src / appl / napsaterm / niftyterm.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-11-17  |  22.3 KB  |  1,032 lines

  1. /* niftyterm.c -- nifty terminal emulator
  2.  *
  3.  * Copyright 1988, 1989 Chris Newman
  4.  * All Rights Reserved
  5.  * Permission is granted to copy, modify, and use this as long
  6.  * as this notice remains intact.  This is a nifty program.
  7.  *
  8.  * Parts of this program were swiped from Joe Keane's jterm, other parts
  9.  * were swiped from ITC's h19 terminal, and still others from gnu-emacs eterm.
  10.  *
  11.  * DISCLAIMER: the author (and maintainer) of this program is not responsible
  12.  * for any damage or other problems caused by it.
  13.  *
  14.  * $Author: ppessi $ $Revision: 1.18 $ $Date: 1993/11/13 04:20:55 $
  15.  */
  16.  
  17. static char rcsid[]=
  18.  "$Id: niftyterm.c,v 1.18 1993/11/13 04:20:55 ppessi Exp ppessi $";
  19.  
  20. #include <stdio.h>
  21. #include <stdlib.h>
  22. #include "nifty.h"
  23. #include "amiga.h"
  24. #include "display.h"
  25. #include "nio.h"
  26.  
  27. /* Correct prototype for the CheckIO.
  28.  * (The one in clib/exec_protos.h has wrong return value type: BOOL (16 bits) 
  29.  * instead of a pointer (32 bits)!)
  30.  */
  31. struct IORequest * CheckIO(struct IORequest *req);
  32.  
  33. #if USE_RLOGIN
  34. #if __SASC
  35. #include <proto/socket.h>
  36. #elif __GNUC__
  37. #include <inline/socket.h>
  38. #else
  39. #include <clib/socket_protos.h>
  40. #endif
  41. #include "rlogin.h"
  42. #endif
  43.  
  44. extern const char version[];
  45. static char copyright[] =
  46. "Original NiftyTerm © Copyright 1990 by Chris Newman and Todd Williamson.\n"
  47. "All Rights Reserved.\n"
  48. "Network and International version © Copyright 1991, 1993 by Pekka Pessi.\n"
  49. "For full copyright information see supporting documentation.\n"
  50. "This is a nifty program.\n";
  51.  
  52. /* Amiga specific stuff */
  53. #define BTOC(bptr) ((void *)((long)(bptr) << 2))
  54. struct GfxBase *GfxBase = NULL;
  55. struct IntuitionBase *IntuitionBase = NULL;
  56. struct DiskfontBase *DiskfontBase = NULL;
  57. extern struct Window *w;
  58. struct timerequest *tr = NULL;
  59. struct MsgPort *tp = NULL;
  60. long _stack = 8192;
  61. long _priority = 0;
  62. long _BackGroundIO = 1;
  63. char *_procname = PROGNAME;
  64. long channel;
  65.  
  66. /* emulation routines */
  67. #if 0
  68. extern char *gettermcap(), *gettermtype();
  69. #endif
  70.  
  71. /* preferences routines */
  72. extern char *getprofile();
  73.  
  74. /* misc.c routines */
  75. extern char *itos();
  76.  
  77. /* keymap.c routine */
  78. struct KeyMap *FindKeyMap(char *);
  79.  
  80. /* imported globals */
  81. extern int emulation;        /* emulation mode */
  82. extern int ansi_LNM;        /* ansi line feed/newline mode */
  83. extern int bell_type;       /* 0 = none, 1 = visual, 2 = audio, 3 = both, 4 = displaybeep() */
  84. extern int pass8;
  85.  
  86. BPTR logfile =    NULL;    /* optional log file */
  87.  
  88. /* Generalized I/O (input from almost anywhere!) */
  89. union {
  90.     struct FileHandle *fh;
  91.     CHANN *chan;
  92.     long sock;
  93. } io = 0;
  94.  
  95. union {
  96.     struct StandardPacket *dos;
  97.     struct IOExtSer *dev;
  98. } in = NULL, out = NULL;
  99.  
  100. struct MsgPort *iop = NULL;
  101. long iomask;
  102.  
  103. enum iotype iotype = 
  104.     (USE_SERIAL ? serial : (USE_DNET ? dnet : (USE_RLOGIN ? rlogin : stdio)));
  105.  
  106. char *bps = "38400";
  107.  
  108. int  
  109.     show_version = 0, 
  110.     wait_niftyterm = 0, 
  111.     unit, shared = 0;
  112.  
  113. #if USE_SERIAL || USE_STDIO
  114. #define INBUFSIZE 512
  115. char inbuf[INBUFSIZE];
  116. #endif
  117.  
  118. #if USE_RLOGIN
  119. /* Quite a hefty buffer - 
  120.  * we don't want to flush anything before OOB
  121.  */
  122. #define BUFSIZE 16324
  123. #else
  124. #define BUFSIZE 4096
  125. #endif
  126. char buf[BUFSIZE], device[64], altismeta = 1;
  127. struct Device *ConsoleDevice = (struct Device *)NULL;
  128. struct IOStdReq console_IO;
  129. int cursormap;
  130. struct Process *me;
  131.  
  132. void
  133. _wb_parse(pp, WBenchMsg)
  134. struct Process *pp;
  135. struct WBStartup *WBenchMsg;
  136. {
  137.     return;
  138. }
  139.  
  140. void
  141. CloseConsole()
  142. {
  143.     if (ConsoleDevice) CloseDevice((struct IORequest *)&console_IO);
  144.     ConsoleDevice = NULL;
  145. }
  146.  
  147. /*
  148.  * set io type depending of the device name
  149.  */
  150. void 
  151. niotype(char *name)
  152. {
  153.     if (!strcmp(name, "dnet")) {
  154.     iotype = dnet;
  155.     } else if (!strcmp(name, "net")) {
  156.     iotype = rlogin;
  157.     } else {
  158.     iotype = serial;
  159.     device = strncpy(device, name, sizeof(device));
  160.     }
  161. }
  162.  
  163. void
  164. nopen(char *host)
  165. {
  166.     me = (struct Process *)FindTask(0L);
  167.  
  168.     switch (iotype) {
  169. #if USE_SERIAL
  170.     case serial: 
  171.     if (!(iop = CreateMsgPort()) ||
  172.         !(in.dev = (struct IOExtSer *)
  173.           CreateIORequest(iop, sizeof(*in.dev))) ||
  174.         !(out.dev = (struct IOExtSer *)
  175.           CreateIORequest(iop, sizeof(*out.dev))) ||
  176.         (in.dev->io_SerFlags |= SERF_RAD_BOOGIE|(shared ? SERF_SHARED : 0),
  177.          OpenDevice(device, unit, (struct IORequest *)in.dev, 0))) {
  178.         if (out.dev) DeleteIORequest(out.dev);
  179.         if (in.dev) DeleteIORequest(in.dev);
  180.         if (iop) DeleteMsgPort(iop);
  181.         fputs("Unable to open ", stderr);
  182.         fputs(device, stderr);
  183.         fputs(" unit ", stderr);
  184.         fputs(itos(unit), stderr);
  185.         fputs(".\n", stderr);
  186.         amigaquit();
  187.         exit(-1);
  188.     }
  189.     iomask = 1 << iop->mp_SigBit;
  190.     *(out.dev) = *(in.dev);
  191.     in.dev->IOSer.io_Command = CMD_READ;
  192.     in.dev->IOSer.io_Data = (APTR)inbuf;
  193.     in.dev->IOSer.io_Length = (ULONG)1;
  194.     in.dev->IOSer.io_Flags = IOB_QUICK;
  195.     SendIO((struct IORequest *)in.dev);
  196.     break;
  197. #endif
  198. #if USE_STDIO
  199.     case stdio: 
  200.     io.fh = (struct FileHandle *)BTOC(me->pr_CIS);
  201.     if (!(iop = CreateMsgPort()) ||
  202.         !(in.dos = (struct StandardPacket *)
  203.           CreateIORequest(iop, sizeof(*in.dos)))) {
  204.         if (in.dos) DeleteIORequest(in.dos);
  205.         if (iop) DeleteMsgPort(iop);
  206.         fputs("Trouble opening stdin\n", stderr);
  207.         amigaquit();
  208.         exit(-1);
  209.     }
  210.     iomask = 1 << iop->mp_SigBit;
  211.     InitDosPkt(in.dos, inbuf, INBUFSIZE);
  212.     PutMsg(io.fh->fh_Type, (struct Message *)in.dos);
  213.     break;
  214. #endif
  215. #if USE_DNET
  216.     case dnet: 
  217.     io.chan = (CHANN *)DOpen(NULL, PORT_IALPHATERM, 20, 15);
  218.     if(!io.chan) {
  219.         fputs("Unable to connect\n", stderr);
  220.         amigaquit();
  221.         exit(-1);
  222.     }
  223.     iomask = 1 << ((struct MsgPort *)io.chan)->mp_SigBit;
  224.     DQueue(io.chan, 32);
  225.     break;
  226. #endif
  227. #if USE_RLOGIN
  228.     case rlogin:
  229.     if (host == NULL) {
  230.         (void)fputs(PROGNAME ": no host specified.\n", stderr);
  231.         amigaquit();
  232.         exit(-1);
  233.     }
  234.     if (SocketBase = OpenLibrary("bsdsocket.library", 2L)) {
  235.         int true = 1;
  236.         struct servent *sp;
  237.         char *temp, *user;
  238.         char remotename[16];    /* hard limit of the rshd */
  239.         char term[16];
  240.  
  241.         SetErrnoPtr(&errno, sizeof(errno));
  242.  
  243.         IO_bit = AllocSignal(-1); 
  244.         URG_bit = AllocSignal(-1); 
  245.       
  246.         iomask = 1 << IO_bit;
  247.         SIGURG = 1 << URG_bit;
  248.  
  249.         SetSocketSignals(SIGBREAKF_CTRL_C, iomask, SIGURG|iomask);
  250.  
  251.         sp = getservbyname("login", "tcp");
  252.         if (sp == NULL) {
  253.         (void)fputs("login/tcp: unknown service.\n", stderr);
  254.         amigaquit();
  255.         exit(-1);
  256.         }
  257.       
  258.         user = getenv("USER");
  259.         if (!user) user = "nobody";
  260.         temp = getprofile(PROGNAME ".remotename");
  261.         strncpy(remotename, temp ? temp : user, sizeof(remotename));
  262.  
  263.         temp = getprofile(PROGNAME ".remotetype");
  264.         strcpy(term, temp ? temp : 
  265.             (emulation == EMU_H19 ? "h19/" :
  266.              (emulation == EMU_VT52 ? "vt52/" : "vt102/")));
  267.         /* sizeof("vt100") == 6 */
  268.         strncat(term, bps, sizeof(term) - 6);
  269.  
  270.         io.sock = rcmd(&host, sp->s_port, user, remotename, term);
  271.         if (io.sock < 0) { amigaquit(); exit(-1); }
  272.  
  273.         /* Set title to remote host name */
  274.         setbasetitle(host);
  275.  
  276.         /* Set Signal driven IO */
  277. #if USE_FIONBIO
  278.         ioctl(io.sock, FIONBIO, (char*)&true); 
  279. #endif
  280.         ioctl(io.sock, FIOASYNC, (char*)&true);
  281.         true = IPTOS_LOWDELAY;
  282.         if (setsockopt(io.sock, IPPROTO_IP, IP_TOS, 
  283.                (char *)&true, sizeof(int)) < 0) {
  284.           perror(PROGNAME ": setsockopt TOS (ignored)");
  285.         }
  286.     } else {
  287.         fputs("Unable to open BSD socket library.\n", stderr);
  288.         amigaquit();
  289.         exit(-1);
  290.     }
  291.     break;
  292. #endif
  293.     default:
  294.     fputs("This version do not support ", stderr);
  295.     fputs(iotype == serial ? "serial devices\n" : 
  296.           (iotype == stdio  ? "AmigaDOS IO\n" :
  297.            (iotype == dnet ? "dnet.\n" : "rlogin protocol\n")), stderr);
  298.     exit(-1);
  299.     }
  300. }
  301.  
  302.  
  303. void 
  304. CloseNiftyIO(void) 
  305. {
  306. #if USE_RLOGIN
  307.     CloseSocketBase();
  308. #endif
  309. }
  310.  
  311. #if USE_STDIO
  312. void
  313. InitDosPkt(pkt, buf, size)
  314. struct StandardPacket *pkt;
  315. char *buf;
  316. long size;
  317. {
  318.     pkt->sp_Msg.mn_Node.ln_Name = (char *)&(pkt->sp_Pkt);
  319.     pkt->sp_Pkt.dp_Link = &pkt->sp_Msg;
  320.     pkt->sp_Pkt.dp_Port = iop;
  321.     pkt->sp_Pkt.dp_Type = ACTION_READ;
  322.     pkt->sp_Pkt.dp_Arg1 = io.fh->fh_Arg1;
  323.     pkt->sp_Pkt.dp_Arg2 = (long)buf;
  324.     pkt->sp_Pkt.dp_Arg3 = size;
  325. }
  326. #endif
  327.  
  328. long
  329. nnread(buf, length)
  330. char *buf;
  331. long length;
  332. {
  333.     switch (iotype) {
  334. #if USE_SERIAL
  335.     case serial: {
  336.     long i, ret, save;
  337.     if(GetMsg(iop)) {
  338.         buf[0] = inbuf[0] & 127;
  339.         in.dev->IOSer.io_Command = SDCMD_QUERY;
  340.         DoIO((struct IORequest *)in.dev);
  341.         save = in.dev->IOSer.io_Actual;
  342.         if(ret = MIN(in.dev->IOSer.io_Actual, length)) {
  343.             in.dev->IOSer.io_Command = CMD_READ;
  344.             in.dev->IOSer.io_Data = (APTR)(buf+1);
  345.             in.dev->IOSer.io_Length = (ULONG)ret;
  346.             DoIO((struct IORequest *)in.dev);
  347.         if(in.dev->IOSer.io_Error) {
  348.             if(in.dev->IOSer.io_Error == 12) 
  349.             termout("\n**** Serial Buffer Overflow;  CLEARING BUFFERS\n", 50);
  350.             else
  351.             termout("**** Serial Device Error; CLEARING BUFFERS\n", 43);
  352.             in.dev->IOSer.io_Command = CMD_CLEAR;
  353.             DoIO((struct IORequest *)in.dev);
  354.         }
  355.         ret = in.dev->IOSer.io_Actual;
  356. #if 0
  357.         for(i=1; i<=ret; i++) 
  358.             buf[i] = buf[i] & 127;
  359. #endif
  360.             }
  361.         in.dev->IOSer.io_Command = CMD_READ;
  362.         in.dev->IOSer.io_Data = (APTR)inbuf;
  363.         in.dev->IOSer.io_Length = (ULONG)1;
  364.         SendIO((struct IORequest *)in.dev);
  365.         return ret + 1;
  366.     }
  367.     else return 0;
  368.     }
  369. #endif
  370. #if USE_STDIO
  371.     case stdio: {
  372.     long ret;
  373.         GetMsg(iop);
  374.     ret = in.dos->sp_Pkt.dp_Res1;
  375.     if(ret) 
  376.         CopyMem(inbuf, buf, ret);
  377.     else ret = -1;
  378.     InitDosPkt(in.dos, inbuf, INBUFSIZE);
  379.     PutMsg(io.fh->fh_Type, (struct Message *)in.dos);
  380.     return ret;
  381.     }
  382. #endif
  383. #if USE_DNET
  384.     case dnet:
  385.     return DNRead(io.chan, buf, length);
  386. #endif
  387. #if USE_RLOGIN
  388.     case rlogin: {
  389.     long n = 0, m; 
  390.     if (SetSignal(0L, SIGURG) & SIGURG) {
  391.         n = rread(io.sock, buf, length);
  392.         if (n >= 0) 
  393.         SetSignal(1 << IO_bit, 1 << IO_bit);
  394.         return n;
  395.     } 
  396.  
  397.     for (;;) {
  398. #if USE_FIONBIO
  399.         m = recv(io.sock, buf + n, length - n, 0);
  400.         if (m < 0) {
  401.         if (errno == EWOULDBLOCK) {
  402.             return n;
  403.         } else {
  404.             return m;
  405.         }
  406.         } else if (m == 0) {
  407.         /* This may be caused by the remote socket shutdown 
  408.          * or OOB data  delivered to the socket.
  409.                  */
  410.         ioctl(io.sock, SIOCATMARK, &m);
  411.         if (m) { 
  412.             SetSignal(SIGURG, SIGURG);
  413.         }
  414.         return n;
  415.         }
  416.         n += m;
  417. #else
  418.         /* Find out how many bytes there are waiting for us */
  419.         if (ioctl(io.sock, FIONREAD, (char*)&m) < 0) {
  420.         perror("nnread FIONREAD");
  421.         return -1;
  422.         }
  423.         if (n + m > length) {
  424.         SetSignal(1 << IO_bit, 1 << IO_bit);
  425.         m = length - n;
  426.         }
  427.         if (m == 0) 
  428.         return n;
  429.         m = recv(io.sock, buf + n, m, 0);
  430.         if (m > 0) {
  431.         n += m;
  432.         } else {
  433.         if (errno == EWOULDBLOCK) 
  434.             return n;
  435.         else
  436.             return m;    /* error */
  437.         }
  438. #endif
  439.     }
  440.     }
  441. #endif
  442.     }
  443. }
  444.  
  445. long
  446. nwrite(buf, length)
  447. char *buf;
  448. long length;
  449. {
  450.     switch (iotype) {
  451. #if USE_SERIAL
  452.     case serial:
  453.         out.dev->IOSer.io_Command = CMD_WRITE;
  454.     out.dev->IOSer.io_Data = (APTR)buf;
  455.     out.dev->IOSer.io_Length = (ULONG)length;
  456.     DoIO((struct IORequest *)out.dev);
  457.     return (long)out.dev->IOSer.io_Actual;
  458. #endif
  459. #if USE_STDIO
  460.     case stdio:
  461.         return Write(me->pr_COS, buf, length);
  462. #endif
  463. #if USE_DNET
  464.     case dnet:
  465.         return DWrite(io.chan, buf, length);
  466. #endif
  467. #if USE_RLOGIN
  468.     case rlogin:
  469.     return send(io.sock, buf, length, 0);
  470. #endif
  471.     }
  472. }
  473.  
  474. void 
  475. niosize(unsigned short ws_row, unsigned short ws_col, 
  476.     unsigned short ws_xpixel, unsigned short ws_ypixel)
  477. {
  478.     switch (iotype) {
  479. #if USE_DNET    
  480.     case dnet:
  481.     DIoctl(io.chan, CIO_SETROWS, ws_row, 0);
  482.            DIoctl(io.chan, CIO_SETCOLS, ws_col, 0);
  483.     break;
  484. #endif
  485. #if USE_RLOGIN
  486.     case rlogin:
  487.     winsize.ws_row    = htons(ws_row);
  488.     winsize.ws_col    = htons(ws_col);
  489.     winsize.ws_xpixel = htons(ws_xpixel);
  490.     winsize.ws_ypixel = htons(ws_ypixel);
  491.  
  492.     if (okwinch) rsendwsize(io.sock);
  493.     
  494.     break;
  495. #endif
  496.     }
  497. }
  498.  
  499. void
  500. nioctl(code, arg1, arg2)
  501. {
  502.     switch (iotype) {
  503. #if USE_SERIAL
  504.     case serial:
  505.     if(code == CIO_FLUSH) {
  506.         out.dev->IOSer.io_Command = CMD_CLEAR;
  507.         DoIO((struct IORequest *)out.dev);
  508.     }
  509.     else if(code == CIO_BREAK) {
  510.         out.dev->IOSer.io_Command = SDCMD_BREAK;
  511.         DoIO((struct IORequest *)out.dev);
  512.     }
  513.     break;
  514. #endif
  515. #if USE_STDIO
  516.     case stdio:
  517.     break;
  518. #endif
  519. #if USE_DNET
  520.     case dnet:
  521.     DIoctl(io.chan, code, arg1, arg2);
  522.     break;
  523. #endif
  524. #if USE_RLOGIN
  525.     case rlogin:
  526.     break;
  527. #endif
  528.     }
  529. }
  530.  
  531. ngetioctl(val, aux)
  532. short *val;
  533. char *aux;
  534. {
  535.     switch (iotype) {
  536. #if USE_SERIAL
  537.     case serial:
  538.     break;
  539. #endif
  540. #if USE_STDIO
  541.     case stdio:
  542.     break;
  543. #endif
  544. #if USE_DNET
  545.     case dnet:
  546.     return DGetIoctl(io.chan, val, aux);
  547. #endif
  548. #if USE_RLOGIN
  549.     case rlogin: 
  550.     break;
  551. #endif
  552.     }
  553.     return -1;
  554. }
  555.  
  556. /* For unlisten mode.  No serial activity may occur after this call until 
  557.  * nunabort() */
  558. int nabort() 
  559. {
  560. #if USE_SERIAL
  561.     if(iotype == serial) {
  562.     AbortIO((struct IORequest *)in.dev);
  563.     WaitIO((struct IORequest *)in.dev);
  564.     return 1;
  565.     }
  566. #endif
  567.     return 0;
  568. }
  569.  
  570. /* undoes nabort().  */
  571. int nunabort()
  572. {
  573. #if USE_SERIAL
  574.     if(iotype == serial) {
  575.     in.dev->IOSer.io_Command = CMD_READ;
  576.     in.dev->IOSer.io_Data = (APTR)inbuf;
  577.     in.dev->IOSer.io_Length = (ULONG)1;
  578.     in.dev->IOSer.io_Flags = IOB_QUICK;
  579.     SendIO((struct IORequest *)in.dev);
  580.     return 1;
  581.     }
  582. #endif
  583.     return 0;
  584. }
  585.  
  586. void
  587. nclose(void)
  588. {
  589.     switch (iotype) {
  590. #if USE_SERIAL
  591.     case serial:
  592.     AbortIO((struct IORequest *)in.dev);
  593.     WaitIO((struct IORequest *)in.dev);
  594.     CloseDevice((struct IORequest *)in.dev);
  595.     DeleteIORequest((struct IORequest *)in.dev);
  596.     DeleteIORequest(out.dev);
  597.     DeleteMsgPort(iop);
  598.     break;
  599. #endif
  600. #if USE_STDIO
  601.     case stdio:
  602.         WaitPort(iop);
  603.     GetMsg(iop);
  604.     DeleteIORequest(in.dos);
  605.     DeleteMsgPort(iop);
  606.     break;
  607. #endif
  608. #if USE_DNET
  609.     case dnet:
  610.         DClose(io.chan);
  611.     break;
  612. #endif
  613. #if USE_RLOGIN
  614.     case rlogin:
  615.     CloseSocket(io.sock);
  616. #endif
  617.     }
  618. }
  619.     
  620. /* die
  621.  */
  622. void 
  623. fatalError(s)
  624. char *s;
  625. {
  626.     fputs(PROGNAME ": ", stderr);
  627.     fputs(s, stderr);
  628.     fputc('\n', stderr);
  629.     dsquit();
  630.     amigaquit();
  631.     exit(-1);
  632. }
  633.  
  634. /* read in assorted preferences
  635.  */
  636. void 
  637. readPreferences()
  638. {
  639.     char    *temp;
  640.  
  641.     if ((temp = getprofile(PROGNAME ".emulation")) != NULL) {
  642.     if (*temp =='v' && temp[1] == 't' && temp[2] == '5')
  643.         emulation = EMU_VT52;
  644.     else if (*temp == 'h' && temp[1] == '1')
  645.         emulation = EMU_H19;
  646.     }
  647.     if ((temp = getprofile(PROGNAME ".bell")) != NULL) {
  648.     if (*temp == 'a')
  649.         bell_type =    2;  /* audio bell */
  650.     else if (*temp == 'v')
  651.         bell_type =    1;  /* visual bell */
  652.     else if (*temp == 'b')
  653.         bell_type = 3;  /* both */
  654.     else if (*temp == 'd')
  655.         bell_type = 4;  /* call displaybeep() for bell */
  656.     else
  657.         bell_type =    0;  /* no bell */
  658.     }
  659.     if((temp = getprofile(PROGNAME ".device")) != NULL) {
  660.     niotype(temp);
  661.     }
  662.     if (temp = getprofile(PROGNAME ".linespeed")) {
  663.     char *newbps = malloc(strlen(temp) + 1);
  664.     if (newbps) 
  665.         bps = strcpy(newbps, temp);
  666.     }
  667.  
  668.     pass8 = getprofileswitch(PROGNAME ".pass8", 1);
  669.     altismeta = getprofileswitch(PROGNAME ".altismeta", 0);
  670. }
  671.  
  672. /* parse the argument list
  673.  */
  674. #define ARGUMENT (*cont ? cont : (argv++, next))
  675. char **parseargs(argv)
  676. char **argv;
  677. {
  678.     char    *cont, *next;
  679.     int        args;
  680.  
  681.     /* loop through until end of list or non-switch argument */
  682.     while (*argv != NULL && **argv == '-' && (*argv)[1]) {
  683.     next = *(argv+1);
  684.     cont = *argv+2;
  685.     switch ((*argv)[1]) {
  686.     case 'B':
  687.         bps = ARGUMENT;
  688.         break;
  689.  
  690.     case '7':
  691.         pass8 = 0;
  692.         break;
  693.  
  694.     case 'd':
  695.         niotype(ARGUMENT);
  696.         break;
  697.         
  698.     case 'h':
  699.         if((*argv)[2] == '1')
  700.         emulation = EMU_H19;
  701.         else
  702.         goto CHECKWM;
  703.         break;
  704.  
  705.     case 's':
  706.         if ((*argv)[2] == 't') {
  707.         wait_niftyterm = 1;
  708.         iotype = stdio;
  709.         } else if(!strcmp(ARGUMENT, "hared"))
  710.         shared =  1;
  711.         else
  712.         goto CHECKWM;
  713.         break;
  714.  
  715.     case 'l':
  716.         logfile = Open(ARGUMENT, MODE_NEWFILE);
  717.         break;
  718.  
  719.     case 'u':
  720.         unit = atoi(ARGUMENT);
  721.         break;
  722.         
  723.     case 'v':
  724.         if ((*argv)[2] != 't')
  725.         goto CHECKWM;
  726.         if ((*argv)[3] == '1')
  727.         emulation = EMU_VT102;
  728.         else if ((*argv)[3] == '5')
  729.         emulation = EMU_VT52;
  730.         else
  731.         goto CHECKWM;
  732.         break;
  733.  
  734.     case 'V':
  735.         show_version = 1;
  736.         break;
  737.  
  738.     case 'w':
  739.         wait_niftyterm = 1;
  740.         break;
  741.  
  742.     case 'N':
  743.         channel = atoi(ARGUMENT);
  744.         break;
  745.  
  746.     default:
  747.     CHECKWM:
  748.         args = dsparsearg((*argv)[1], cont, next);
  749.         if (!args)
  750.         goto USAGE;
  751.         argv+=args-1;
  752.         break;
  753.     }
  754.     argv++;
  755.     }
  756.  
  757.     return (argv);
  758.  
  759.     USAGE:
  760.     puts("Usage: " PROGNAME " [-option ...]\n"
  761.      "Available " PROGNAME " options are:\n"
  762.      "  -V              show version number & copyright notice\n"
  763.      "  -h19            emulate an h19 instead of a vt102 terminal\n"
  764.      "  -vt52           emulate a vt52 on startup\n"
  765.      "  -vt102          emulate a vt102 on startup (default emulation)\n"
  766.      "  -l <file>       write all output to a log file\n"
  767.      "  -st             take input from stardard input.\n"
  768.      "  -d <devicename> specify device to use (e.g. serial.device)\n"
  769.      "  -u <unit #>     specify unit number to use (see -d)\n"
  770.      "  -B <linespeed>  specify line speed to use\n"
  771.          "  -N <net>        give DNet network number\n"
  772.          "  -shared         open device in shared mode\n"
  773.          "  -7              strip 8th bit of character codes\n"
  774.      "  -w              wait after program ends before closing window.");
  775.     dsshowusage();
  776.     exit(0);
  777.     /*NOTREACHED*/
  778. }
  779.  
  780. /* This allows terminal answerback messages
  781.  */
  782. int write_to_tty(buf, count)
  783. char    *buf;
  784. int    count;
  785. {
  786.     if (iotype != stdio)
  787.     return (nwrite(buf, count));
  788.     dsputs(buf);
  789.     return (count);
  790. }
  791.  
  792. void
  793. amigainit(void)
  794. {
  795.     GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", 0);
  796.     IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", 0);
  797.     DiskfontBase = (struct DiskfontBase *)OpenLibrary("diskfont.library", 0);
  798.     if (!GfxBase || !IntuitionBase || !DiskfontBase ||
  799.     !(tp = CreateMsgPort()) ||
  800.     !(tr = (void *)CreateIORequest(tp, sizeof(*tr)))) {
  801.         puts("Problem during initialization.\n"
  802.          "A needed library or resource was not found.\n");
  803.     amigaquit();
  804.     }
  805.     if(OpenDevice(TIMERNAME, UNIT_VBLANK, (struct IORequest *)tr, 0)) {
  806.         puts("Problem opening timer device");
  807.     amigaquit();
  808.     exit(-1);
  809.     }    
  810. }
  811.  
  812. void
  813. amigaquit(void)
  814. {
  815.     if(tr) {
  816.         CloseDevice((struct IORequest *)tr);
  817.         DeleteIORequest((struct IORequest *)tr);
  818.     }
  819.     if (tp) DeleteMsgPort(tp);
  820.  
  821.     CloseNiftyIO();
  822.  
  823.     CloseConsole();
  824.     if(GfxBase) CloseLibrary(GfxBase);
  825.     if(IntuitionBase) CloseLibrary(IntuitionBase);
  826.     if(DiskfontBase) CloseLibrary(DiskfontBase);
  827.     if(logfile) Close(logfile);
  828. }
  829.  
  830. /* Event handler for intuition events.
  831.  */
  832. void
  833. do_IntuiMessage()
  834. {
  835.     struct IntuiMessage *msg;
  836.     int count;
  837.     
  838.     while(msg = (struct IntuiMessage *)GetMsg(w->UserPort)) {
  839.         switch(msg->Class) {
  840.         case RAWKEY:
  841.             do_RawKey(msg);
  842.         break;
  843.             case CLOSEWINDOW:
  844.                 ReplyMsg((struct Message *)msg);
  845.         nclose();
  846.                 dsquit();
  847.             amigaquit();
  848.             exit(0);
  849.             break;
  850.         case NEWSIZE:
  851.         ReplyMsg((struct Message *)msg);
  852.                 redraw_display(1);
  853.         break;
  854.         case MENUPICK:
  855.             if(count = domenu(msg, buf, sizeof(buf)))
  856.             nwrite(buf, count);
  857.         break;
  858.         case MOUSEMOVE:
  859.         case MOUSEBUTTONS:
  860.             if(count = domouse(msg, buf, sizeof(buf)))
  861.             nwrite(buf, count);
  862.         ReplyMsg((struct Message *)msg);
  863.         break;
  864. #ifdef OWNICONIFY
  865.         case GADGETDOWN:
  866.             if(DoubleClick(secs, mics, msg->Seconds, msg->Micros)) {
  867.             ReplyMsg((struct Message *)msg);
  868.             while(msg = (struct IntuiMessage *)GetMsg(w->UserPort)) ReplyMsg((struct Message *)msg);
  869.             deiconify();
  870.                    mapwindow();
  871.         }
  872.         else {
  873.                     secs = msg->Seconds; mics = msg->Micros;
  874.             ReplyMsg((struct Message *)msg);
  875.         }
  876.         break; 
  877. #endif
  878.             default:
  879.                 ReplyMsg((struct Message *)msg);
  880.         }
  881.     }
  882. }
  883.  
  884. void 
  885. HandleSetWinSize(struct Window *win, short rows, short cols)
  886. {
  887.     short height, width;
  888.     short dx, dy;
  889.     
  890.     width = cols*win->RPort->TxWidth + win->BorderLeft + win->BorderRight;
  891.     height = rows*win->RPort->TxHeight+win->BorderTop+win->BorderBottom;
  892.     dx = win->WScreen->Width - (win->LeftEdge+width);
  893.     if(dx > 0)
  894.     dx = 0;
  895.     if(-dx > win->LeftEdge) {
  896.     dx = -win->LeftEdge;
  897.     width = win->WScreen->Width;
  898.     }
  899.         
  900.     dy = win->WScreen->Height - (win->TopEdge + height);
  901.     if(dy > 0) 
  902.     dy = 0;
  903.     if(-dy > win->TopEdge) {
  904.     dy = -win->TopEdge;
  905.     height = win->WScreen->Height;
  906.     }
  907.         
  908.     if(dx || dy) {
  909.     MoveWindow(win, dx, dy);
  910.     }
  911.     if(win->Width != width || win->Height != height) {
  912.     SizeWindow(win, width - win->Width, height - win->Height);
  913.     }
  914. }
  915.  
  916. void
  917. HandleIoctl(cmd, val, aux, win)
  918. short cmd, val;
  919. char aux;
  920. struct Window *win;
  921. {
  922. #if USE_DNET
  923.     static short saverows;
  924.  
  925.     if (iotype == dnet) {
  926.     switch (cmd) {
  927. #if 0
  928.     case CIO_MODE:
  929.         Cooked = val;
  930.         break;
  931. #endif
  932.     case CIO_SETROWS:
  933.         saverows = val;
  934.         return;
  935.     case CIO_SETCOLS:
  936.         HandleSetWinSize(win, saverows, val);
  937.         return;
  938.     }
  939.     } 
  940. #endif
  941. }
  942.  
  943. void
  944. do_IOinput()
  945. {
  946.     int n;
  947.  
  948.     if((n = nnread(buf, BUFSIZE)) > 0) {
  949.     if(logfile != (BPTR) NULL && n && (Write(logfile, buf, n) != n)) {
  950.         Close(logfile);
  951.         logfile = (BPTR) NULL;
  952.         fputs("Error writing to log file", stderr);
  953.     }
  954.     termout(buf, n);
  955.     }
  956.     else if (n == -2) {
  957.     short val, cmd;
  958.     char aux;
  959.     cmd = ngetioctl(&val, &aux);
  960.     if (cmd != -1)
  961.         HandleIoctl(cmd, val, aux, w);
  962.     }
  963.     else if(n < 0) {
  964.     if(wait_niftyterm) {
  965.         dscursoroff();
  966.         dscursormove(NEXT_LINE, 1);
  967.         (void) dsstyle(INVERSE1);
  968.         dsputs("** Press any key to exit. **");
  969.         dscursoron();
  970.         WaitPort(w->UserPort);
  971.         while(GetMsg(w->UserPort));
  972.     }
  973.     dsquit();
  974.     amigaquit();
  975.     exit(0);
  976.     }
  977. }
  978.  
  979. /*******************
  980.  * niftyterm entry point
  981.  */
  982. /*ARGSUSED*/
  983. main(argc, argv)
  984. int    argc;
  985. char    **argv;
  986. {
  987.     long winmask, timemask, mask;
  988.  
  989.     amigainit();
  990.     dsinit();
  991.     readPreferences();
  992.     argv = parseargs(argv+1);
  993.     if (iotype == stdio) {
  994.     if (show_version) {
  995.         puts(version);
  996.         puts(copyright);
  997.     }
  998.     } 
  999.  
  1000.     ansi_LNM = iotype == serial;
  1001.  
  1002.     /* nopen() should be called before dsstart() because it sets the title.. */
  1003.     nopen(*argv); 
  1004.     dsstart();
  1005.     timemask = 1 << tp->mp_SigBit;
  1006.     
  1007.     for (;;) {
  1008.     dscheckflash();
  1009.  
  1010.         tr->tr_time.tv_secs = 1;
  1011.         tr->tr_time.tv_micro = 0;
  1012.     tr->tr_node.io_Command = TR_ADDREQUEST;
  1013.     SendIO((struct IORequest *)tr);
  1014.         winmask = 1 << w->UserPort->mp_SigBit;
  1015.     mask = Wait(iomask | winmask | timemask);
  1016.  
  1017.     if(!((mask & timemask)&&(CheckIO((struct IORequest *)tr)))) 
  1018.         AbortIO((struct IORequest *)tr);
  1019.         WaitIO((struct IORequest *)tr);
  1020.     SetSignal(0, timemask); /* In case WaitIO didn't do it for me... */
  1021.  
  1022.     if(mask & winmask) {
  1023.         do_IntuiMessage();
  1024.     }
  1025.  
  1026.     if(mask & iomask) {
  1027.         do_IOinput();
  1028.         }
  1029.     }    
  1030.     /*NOTREACHED*/
  1031. }
  1032.